home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 4
/
Aminet 4 - November 1994.iso
/
aminet
/
comm
/
net
/
dnet_src.lha
/
dnet
/
amiga
/
dnetdev.old
/
dnet.c
next >
Wrap
C/C++ Source or Header
|
1990-12-11
|
15KB
|
721 lines
/*
* DNET.C
*
* DNet device dnet.device
*
* Simulates a serial device using dnet.
*
* This code is based on Matt Dillon's fms.device. (In fact whatever did not need
* changing did not get changed).
*
* Written by Karl R. Hakimian
*
* Bugs & Limits
* Only one read can be done at a time. A second read queued will abort the first
* read.
* SDCMD_BREAK, SDCMD_SETPARAMS are not supported.
*
* Modification History
* 11-24-90 Karl Hakimian Original coding (hacking of fms.device)
* 12-02-90 Bug fixes support for SDCMD_QUERY added.
*/
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/errors.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <devices/serial.h>
#include <devices/timer.h>
#include <libraries/dosextens.h>
/*#define DEBUG 1*/
#ifdef DEBUG
int d_out;
#endif
long DOSBase = NULL;
#define ABORTED (1<<5)
#define CMD_ABORTREQ (0x7FF0)
#define CMD_KILLPROC (0x7FF1)
#define CMD_STARTUP (0x7FF1)
void CoProc();
extern int TagDevOpen();
extern int TagDevClose();
extern int TagDevExpunge();
extern int TagDevBeginIO();
extern int TagDevAbortIO();
extern void *CreateProc();
extern void *CreatePort();
extern void *AllocMem();
extern void DUMmySeg();
typedef struct Library LIB;
typedef struct Device DEV;
typedef struct Process PROC;
typedef struct MsgPort PORT;
typedef struct Message MSG;
typedef struct List LIST;
typedef struct Node NODE;
typedef long (*func_ptr)();
typedef struct {
PORT *Port;
} NDUnit;
typedef struct {
LIB Lib;
char *Host; /* NULL. I will do something with this when Matt does. */
int Id;
} NDev;
/* Taken from dnet:amiga/lib/dnetlib.h */
typedef unsigned char ubyte;
typedef unsigned short uword;
#define CHANN struct _CHANN
CHANN {
PORT port; /* receive data, replies */
PORT *dnetport; /* dnet's master port */
LIST rdylist; /* ready to be read */
uword chan; /* channel # for open channels */
ubyte eof; /* channel remotely closed/eof */
ubyte filler;
int qlen; /* allowed write queue size */
int queued; /* current # packets queued */
};
#define DNCMD_WRITE 36 /* Write data to a channel */
typedef struct IOStdReq IOSTD;
/* End of dnet stuff */
typedef struct IOExtSer IOB;
extern char DeviceName[];
extern char IdString[];
long SysBase = NULL;
NDev *DevBase = NULL;
APTR DevSegment = NULL;
NDev *
Init(seg)
APTR seg;
{
static func_ptr DevVectors[] = {
(func_ptr)TagDevOpen,
(func_ptr)TagDevClose,
(func_ptr)TagDevExpunge,
NULL,
(func_ptr)TagDevBeginIO,
(func_ptr)TagDevAbortIO,
(func_ptr)-1
};
NDev *db;
SysBase = *(long *)4;
DOSBase = OpenLibrary("dos.library",0);
if (DOSBase == NULL)
return(NULL);
DevBase = db = (NDev *)MakeLibrary((long **)DevVectors,NULL,NULL,sizeof(NDev),NULL);
db->Lib.lib_Node.ln_Type = NT_DEVICE;
db->Lib.lib_Node.ln_Name = DeviceName;
db->Lib.lib_Flags = LIBF_CHANGED|LIBF_SUMUSED;
db->Lib.lib_Version = 1;
db->Lib.lib_IdString= (APTR)IdString;
db->Host = NULL;
db->Id = 0;
DevSegment = seg;
AddDevice((DEV *)db);
#ifdef DEBUG
d_out = Open("con:0/0/320/200/Debug", 1006);
#endif
return(db);
}
NDev *
DevOpen(unitnum, iob, flags)
long unitnum;
IOB *iob;
long flags;
{
NDUnit *unit;
IOB siob;
ULONG port;
char temp[32];
int id;
int i;
#ifdef DEBUG
Write(d_out,"Open\n",5);
#endif
if ((unit = (NDUnit *)AllocMem(sizeof(NDUnit),MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
iob->IOSer.io_Error = IOERR_OPENFAIL;
iob->IOSer.io_Device = NULL;
return(DevBase);
}
DevBase->Lib.lib_OpenCnt++;
id = DevBase->Id++;
/*
Initialize CoProc process.
*/
sprintf(temp,"DNet %d",id);
port = (ULONG)CreateProc(temp, 0, (long)DUMmySeg >> 2, 4096);
sprintf(temp,"%x",port);
if ((siob.IOSer.io_Message.mn_ReplyPort = CreatePort(NULL,0)) == NULL) {
DevBase->Lib.lib_OpenCnt--;
FreeMem(unit,sizeof(NDUnit));
iob->IOSer.io_Error = IOERR_OPENFAIL;
iob->IOSer.io_Device = NULL;
return(DevBase);
}
siob.IOSer.io_Command = CMD_STARTUP;
siob.IOSer.io_Data = (APTR)unitnum;
siob.IOSer.io_Length = -1;
/*
Lookup for childs port. Timeout in 10 seconds.
*/
for (i = 0; i < 10 && !(unit->Port = (PORT *)FindPort(temp)); i++)
Delay(50);
if (unit->Port == NULL) {
iob->IOSer.io_Error = IOERR_OPENFAIL;
iob->IOSer.io_Device = NULL;
DevBase->Lib.lib_OpenCnt--;
FreeMem(unit,sizeof(NDUnit));
DeletePort(siob.IOSer.io_Message.mn_ReplyPort);
return(DevBase);
}
/*
Send startup message.
*/
PutMsg(unit->Port,&siob.IOSer.io_Message);
WaitPort(siob.IOSer.io_Message.mn_ReplyPort);
(void)GetMsg(siob.IOSer.io_Message.mn_ReplyPort);
DeletePort(siob.IOSer.io_Message.mn_ReplyPort);
/*
If there was an error on startup then quit.
*/
if (siob.IOSer.io_Error) {
DevBase->Lib.lib_OpenCnt--;
FreeMem(unit,sizeof(NDUnit));
iob->IOSer.io_Error = IOERR_OPENFAIL;
iob->IOSer.io_Device = NULL;
return(DevBase);
}
/*
Initialize device and io request structure.
*/
DevBase->Lib.lib_Flags &= ~LIBF_DELEXP;
iob->IOSer.io_Unit = (struct NDUnit *)unit;
iob->IOSer.io_Error = 0;
return(DevBase);
}
APTR
DevExpunge()
{
if (DevSegment == NULL)
Alert(24, (char *)24);
if (DevBase->Lib.lib_OpenCnt) {
DevBase->Lib.lib_Flags |= LIBF_DELEXP;
return(NULL);
}
Remove((NODE *)DevBase);
CloseLibrary(DOSBase);
FreeMem((char *)DevBase - DevBase->Lib.lib_NegSize, DevBase->Lib.lib_NegSize + DevBase->Lib.lib_PosSize);
#ifdef DEBUG
Close(d_out);
#endif
return(DevSegment);
}
APTR
DevClose(iob)
IOB *iob;
{
IOB kiob;
NDUnit *unit;
unit = (NDUnit *)iob->IOSer.io_Unit;
if (unit == NULL || DevBase->Lib.lib_OpenCnt == 0)
return(NULL);
/*
Kill CoProc if it is still there.
*/
if (unit->Port) {
kiob.IOSer.io_Message.mn_ReplyPort = CreatePort(NULL, 0);
kiob.IOSer.io_Command = CMD_KILLPROC;
PutMsg(unit->Port, &kiob.IOSer.io_Message);
WaitPort(kiob.IOSer.io_Message.mn_ReplyPort);
DeletePort(kiob.IOSer.io_Message.mn_ReplyPort);
}
FreeMem(unit,sizeof(NDUnit));
if (DevBase->Lib.lib_OpenCnt && --DevBase->Lib.lib_OpenCnt)
return(NULL);
if (DevBase->Lib.lib_Flags & LIBF_DELEXP)
return(DevExpunge());
/*
* close down resources
*/
return(NULL);
}
void
DevBeginIO(iob)
IOB *iob;
{
NDUnit *unit;
IOB *fiob;
unit = (NDUnit *)iob->IOSer.io_Unit;
#ifdef DEBUG
Write(d_out,"BeginIO\n",8);
#endif
if (unit->Port == NULL) {
iob->IOSer.io_Error = SerErr_LineErr;
ReplyMsg(&iob->IOSer.io_Message);
return;
}
iob->IOSer.io_Error = 0;
iob->IOSer.io_Actual = 0;
switch(iob->IOSer.io_Command) {
case CMD_INVALID:
iob->IOSer.io_Error = IOERR_NOCMD;
break;
case CMD_RESET:
#ifdef DEBUG
Write(d_out,"RESET\n",6);
#endif
Forbid();
while ((fiob = (IOB *)GetMsg(unit->Port))) {
fiob->IOSer.io_Flags |= ABORTED;
ReplyMsg(fiob);
}
Permit();
PutMsg(unit->Port, &iob->IOSer.io_Message);
iob->IOSer.io_Flags &= ~IOF_QUICK;
iob = NULL;
break;
case CMD_READ:
#ifdef DEBUG
Write(d_out,"READ\n",5);
#endif
PutMsg(unit->Port, &iob->IOSer.io_Message);
iob->IOSer.io_Flags &= ~IOF_QUICK; /* not quick */
iob = NULL;
break;
case CMD_WRITE:
#ifdef DEBUG
Write(d_out,"WRITE\n",6);
#endif
PutMsg(unit->Port, &iob->IOSer.io_Message);
iob->IOSer.io_Flags &= ~IOF_QUICK; /* not quick */
iob = NULL;
break;
case CMD_CLEAR:
#ifdef DEBUG
Write(d_out,"CLEAR\n",6);
#endif
PutMsg(unit->Port, &iob->IOSer.io_Message);
iob->IOSer.io_Flags &= ~IOF_QUICK;
iob = NULL;
break;
case CMD_FLUSH:
#ifdef DEBUG
Write(d_out,"FLUSH\n",6);
#endif
Forbid();
while ((fiob = (IOB *)GetMsg(unit->Port))) {
fiob->IOSer.io_Flags |= ABORTED;
ReplyMsg(fiob);
}
Permit();
break;
case SDCMD_QUERY:
#ifdef DEBUG
Write(d_out,"QUERY\n",6);
#endif
PutMsg(unit->Port, &iob->IOSer.io_Message);
iob->IOSer.io_Flags &= ~IOF_QUICK;
iob = NULL;
break;
case CMD_STOP:
case CMD_START:
case SDCMD_SETPARAMS:
case SDCMD_BREAK:
#ifdef DEBUG
Write(d_out,"OTHER\n",6);
#endif
break;
default:
#ifdef DEBUG
Write(d_out,"BAD\n",4);
#endif
iob->IOSer.io_Error = IOERR_NOCMD;
break;
}
if (iob) {
if ((iob->IOSer.io_Flags & IOF_QUICK) == 0)
ReplyMsg((MSG *)iob);
}
}
DevAbortIO(iob)
IOB *iob;
{
IOB aiob;
IOB *riob;
NDUnit *unit;
struct List *l;
unit = (NDUnit *)iob->IOSer.io_Unit;
if (unit->Port == NULL) {
iob->IOSer.io_Flags |= ABORTED;
ReplyMsg(iob);
return(IOERR_ABORTED);
}
l = &unit->Port->mp_MsgList;
/*
Search for the request in the message queue.
*/
#ifdef DEBUG
Write(d_out,"AbortIO\n",8);
#endif
Forbid();
for (riob = (IOB *)l->lh_Head; riob; riob = (IOB *)(((struct Node *)riob)->ln_Succ)) {
/*
Request found, remove it.
*/
if (riob == iob) {
Remove((struct Node *)riob);
iob->IOSer.io_Flags |= ABORTED;
break;
}
}
Permit();
/*
If the request was not found, Tell CoProc to abort.
*/
if (!riob) {
if ((aiob.IOSer.io_Message.mn_ReplyPort = CreatePort(NULL,0)) == NULL)
return(NULL);
aiob.IOSer.io_Command = CMD_ABORTREQ;
aiob.IOSer.io_Data = (APTR)iob;
aiob.IOSer.io_Length = -1;
PutMsg(unit->Port, &aiob.IOSer.io_Message);
WaitPort(aiob.IOSer.io_Message.mn_ReplyPort);
DeletePort(aiob.IOSer.io_Message.mn_ReplyPort);
}
else
ReplyMsg(riob);
if (iob->IOSer.io_Flags & ABORTED)
return(IOERR_ABORTED);
return(0);
}
/*
* SERVER SIDE (IS A PROCESS)
*/
void
CoProc()
{
IOB *iob;
IOSTD *dnreq;
NDUnit *unit;
PROC *proc;
PORT *port;
char notdone = 1;
int toread;
int haveread;
int read;
int data_ready = 0;
IOB *riob=NULL;
char pname[32];
int Chan;
int cmask;
int dmask;
int sig;
#ifdef DEBUG
char buf[256];
#endif
/*
Create command message port.
*/
proc = (PROC *)FindTask(NULL);
sprintf(pname,"%x",&(proc->pr_MsgPort));
if ((port = CreatePort(pname,0)) == NULL) {
return;
}
/*
Wait for startup message.
*/
(void)Wait(1 << port->mp_SigBit);
iob = (IOB *)GetMsg(port);
if (iob->IOSer.io_Command != CMD_STARTUP || (Chan = DOpen(DevBase->Host,iob->IOSer.io_Data)) == NULL) {
iob->IOSer.io_Error = IOERR_OPENFAIL;
ReplyMsg(&iob->IOSer.io_Message);
DeletePort(port);
return;
}
iob->IOSer.io_Error = 0;
ReplyMsg(&iob->IOSer.io_Message);
DQueue(Chan,128);
dmask = 1 << ((PORT *)Chan)->mp_SigBit;
cmask = 1 << port->mp_SigBit;
#ifdef DEBUG
sprintf(buf,"dmask = %xx, cmask = %xx\n",dmask,cmask);
Write(d_out,buf,strlen(buf));
#endif
while (notdone) {
sig = Wait(cmask|dmask);
if (sig&cmask) {
while (iob = (IOB *)GetMsg(port)) {
unit = (NDUnit *)iob->IOSer.io_Unit;
switch(iob->IOSer.io_Command) {
case CMD_ABORTREQ:
#ifdef DEBUG
Write(d_out,"ABORT\n",6);
#endif
if (iob->IOSer.io_Data == (APTR)riob) {
riob->IOSer.io_Flags |= ABORTED;
ReplyMsg(&riob->IOSer.io_Message);
riob = NULL;
}
break;
case CMD_RESET:
#ifdef DEBUG
Write(d_out,"RESET\n",6);
#endif
if (riob) {
riob->IOSer.io_Flags |= ABORTED;
ReplyMsg(&riob->IOSer.io_Message);
}
/*
We want to fall through to clear.
*/
case CMD_CLEAR:
#ifdef DEBUG
Write(d_out,"CLEAR\n",6);
#endif
/*
Remove all data from the read buffer.
*/
while (DNRead(Chan,(char *)&data_ready,1))
;
data_ready = 0;
break;
case SDCMD_QUERY:
#ifdef DEBUG
Write(d_out,"QUERY\n",5);
#endif
iob->io_Status = 0xf8;
Forbid();
for (dnreq = (IOSTD *)((CHANN *)Chan)->rdylist.lh_Head; dnreq; dnreq = (IOSTD *)((struct Node *)dnreq)->ln_Succ) {
if (dnreq->io_Command == DNCMD_WRITE)
iob->IOSer.io_Actual += dnreq->io_Length - dnreq->io_Actual;
}
for (dnreq = (IOSTD *)((CHANN *)Chan)->port.mp_MsgList.lh_Head; dnreq; dnreq = (IOSTD *)((struct Node *)dnreq)->ln_Succ) {
if (dnreq->io_Command == DNCMD_WRITE)
iob->IOSer.io_Actual += dnreq->io_Length - dnreq->io_Actual;
}
Permit();
break;
case CMD_KILLPROC:
#ifdef DEBUG
Write(d_out,"KILL\n",5);
#endif
goto exit_proc;
break;
case CMD_READ:
#ifdef DEBUG
Write(d_out,"READ\n",5);
#endif
/*
Currently only allows one read at a time. If a read request comes in while one
is still pending then abort the first read.
*/
if (riob) {
riob->IOSer.io_Error = SerErr_LineErr;
ReplyMsg(&riob->IOSer.io_Message);
riob = NULL;
}
toread = iob->IOSer.io_Length;
haveread = 0;
riob = iob;
iob = NULL;
break;
case CMD_WRITE:
#ifdef DEBUG
Write(d_out,"WRITE\n",6);
#endif
if (iob->IOSer.io_Length >= 0)
iob->IOSer.io_Actual = DWrite(Chan, (char *)iob->IOSer.io_Data, iob->IOSer.io_Length);
else if (iob->IOSer.io_Length == -1)
iob->IOSer.io_Actual = DWrite(Chan, (char *)iob->IOSer.io_Data, strlen((char *)iob->IOSer.io_Data));
else
iob->IOSer.io_Actual = iob->IOSer.io_Length;
if (iob->IOSer.io_Actual < 0) {
iob->IOSer.io_Error = SerErr_LineErr;
goto exit_proc;
}
break;
default:
iob->IOSer.io_Error = SerErr_LineErr;
break;
}
if (iob)
ReplyMsg(&iob->IOSer.io_Message);
}
}
/*
Do the read if there is data and a pending read request.
*/
if (((sig&dmask) || data_ready) && riob) {
if (toread == -1) {
while (riob && (read = DNRead(Chan,(char *)&riob->IOSer.io_Data[haveread],1))) {
if ((char *)&riob->IOSer.io_Data[haveread] == '\0') {
riob->IOSer.io_Actual = haveread;
ReplyMsg(&riob->IOSer.io_Message);
riob = NULL;
toread = haveread = 0;
}
haveread++;
}
continue;
}
read = DNRead(Chan, (char *)&riob->IOSer.io_Data[haveread], toread);
if (read < 0) {
riob->IOSer.io_Error = SerErr_LineErr;
ReplyMsg(&riob->IOSer.io_Message);
iob = NULL;
goto exit_proc;
}
else if (read == 0)
data_ready = 0;
else {
data_ready = 1; /* data_read is true until no data is left. */
haveread += read;
toread -= haveread;
}
if (toread <= 0) {
riob->IOSer.io_Actual = haveread;
ReplyMsg(&riob->IOSer.io_Message);
riob = NULL;
toread = haveread = 0;
}
}
else if (sig&dmask) /* There is data ready so record rember it. */
data_ready = 1;
}
/* fall through to exit */
Forbid(); /* Forbid before exiting. */
return;
exit_proc:
#ifdef DEBUG
Write(d_out,"exiting\n",8);
#endif
if (riob) {
riob->IOSer.io_Error = SerErr_LineErr;
ReplyMsg(&riob->IOSer.io_Message);
}
DClose(Chan);
#ifdef DEBUG
Write(d_out,"DNET closed\n",12);
#endif
while (riob = (IOB *)GetMsg(port)) {
riob->IOSer.io_Error = SerErr_LineErr;
riob->IOSer.io_Flags |= ABORTED;
ReplyMsg(&riob->IOSer.io_Message);
}
DeletePort(port);
unit->Port = NULL;
#ifdef DEBUG
Write(d_out,"Port gone\n",10);
#endif
Forbid(); /* Forbid before exiting. */
if (iob)
ReplyMsg(&iob->IOSer.io_Message);
}